Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: use primordials in extensions/web #11273

Merged
merged 9 commits into from
Jul 6, 2021

Conversation

bartlomieju
Copy link
Member

Ref #11224

@bartlomieju bartlomieju mentioned this pull request Jul 4, 2021
67 tasks
Co-authored-by: Divy Srivastava <dj.srivastava23@gmail.com>
Co-authored-by: Divy Srivastava <dj.srivastava23@gmail.com>
Copy link
Contributor

@SimonRask SimonRask left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

08_text_encoding.js - line 389 TypedArrayPrototypeSlice

extensions/web/05_base64.js Outdated Show resolved Hide resolved
@SimonRask
Copy link
Contributor

.slice() if you forgot :)

@bartlomieju
Copy link
Member Author

.slice() if you forgot :)

Thanks, fixed

Copy link
Member

@lucacasonato lucacasonato left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update Uint8Array.from on line 65 of base64.js

@@ -373,14 +388,16 @@
if (BOMEncoding === "UTF-8") start = 3;
else start = 2;
}
return new TextDecoder(encoding).decode(bytes.slice(start));
return new TextDecoder(encoding).decode(
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should use TextEncoderPrototypeDecode

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto in text_encoding:

return new TextDecoder(encoding).decode(

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TextEncoderPrototypeDecode does not exist. Primordials are only for JS builtins

Copy link

@ghost ghost Jul 6, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TextEncoderPrototypeDecode does not exist. Primordials are only for JS builtins

It's prone to prototype manipulation, and that is the purpose of the existance of the primordials in general. Or are they more narrow in their scope/goal?

I see these as things that should be created, because, although I haven't checked the relevant spec for this algorithm, I doubt it specifies performing an ECMAScript Get operation on a TextDecoder instance.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Primordials are limited to JS builtins not external APIs (analogous to its name). Node.js doesn't do TextEncoderPrototypeDecode either

Copy link

@ghost ghost Jul 6, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If that is so, then all of my comments here besides the ones about DataView and TypedArray can be discarded/ignored.

Although, why should Deno aim to only do as little as Node.js had?

@ghost
Copy link

ghost commented Jul 6, 2021

These property accesses should directly use prototype getters: ArrayBufferPrototypeGetByteLength, DataViewPrototypeGetByteLength, TypedArrayPrototypeGetLength. I'm iffy about this line because it accesses a dynamic prototype get accessor, I'd suggest maybe doing something more like

let getByteOffset;
if (value instanceof DataView) {
  length = DataViewPrototypeGetByteLength(value);
  getByteOffset = DataViewPrototypeGetByteOffset;
} else {
  length = TypedArrayPrototypeGetLength(value)
  getByteOffset = TypedArrayPrototypeGetByteOffset;
}

return new (value.constructor)(
  clonedBuffer,
  getByteOffset(value),
  length,
);

also iffy about line 56's buffer access. You'll need an extra branch to get the correct get accessor for the buffer.

This u8 array construction requires an extra branch and usage of primordial accessors.

@ghost
Copy link

ghost commented Jul 6, 2021

(Unrelated to this PR, but the abort_signal file seem to be missing WebIDL assertions on getters and such, is that handled in configurePrototype?)

Line 107 should use AbortSignalPrototypeGetAborted. I also believe that EventTargetPrototypeDispatchEvent should be used here?

@ghost
Copy link

ghost commented Jul 6, 2021

Apologies for being as pedantic as I already was, but lastly, the location file needs to use URLPrototypeGet... accessors. :)

@littledivy
Copy link
Member

These property accesses should directly use prototype getters: ArrayBufferPrototypeGetByteLength, DataViewPrototypeGetByteLength, TypedArrayPrototypeGetLength. I'm iffy about this line because it accesses a dynamic prototype get accessor, I'd suggest maybe doing something more like

let getByteOffset;
if (value instanceof DataView) {
  length = DataViewPrototypeGetByteLength(value);
  getByteOffset = DataViewPrototypeGetByteOffset;
} else {
  length = TypedArrayPrototypeGetLength(value)
  getByteOffset = TypedArrayPrototypeGetByteOffset;
}

return new (value.constructor)(
  clonedBuffer,
  getByteOffset(value),
  length,
);

also iffy about line 56's buffer access. You'll need an extra branch to get the correct get accessor for the buffer.

This u8 array construction requires an extra branch and usage of primordial accessors.

@crimsoncodes0 get accessors of internal primordial objects (eg window.__bootstrap.Dataview) are not exposed to userland; hence they are not vulnerable to prototype pollution

@ghost
Copy link

ghost commented Jul 6, 2021

These property accesses should directly use prototype getters: ArrayBufferPrototypeGetByteLength, DataViewPrototypeGetByteLength, TypedArrayPrototypeGetLength. I'm iffy about this line because it accesses a dynamic prototype get accessor, I'd suggest maybe doing something more like

let getByteOffset;
if (value instanceof DataView) {
  length = DataViewPrototypeGetByteLength(value);
  getByteOffset = DataViewPrototypeGetByteOffset;
} else {
  length = TypedArrayPrototypeGetLength(value)
  getByteOffset = TypedArrayPrototypeGetByteOffset;
}

return new (value.constructor)(
  clonedBuffer,
  getByteOffset(value),
  length,
);

also iffy about line 56's buffer access. You'll need an extra branch to get the correct get accessor for the buffer.
This u8 array construction requires an extra branch and usage of primordial accessors.

@crimsoncodes0 get accessors of internal primordial objects (eg window.__bootstrap.Dataview) are not exposed to userland; hence they are not vulnerable to prototype pollution

Can you explain what you mean by that, and how it pertains to the code in question?
Was your comment referring to when I'd said

because it accesses a dynamic prototype get accessor

in particular? If not, can you specify which part of my comment you were replying to?

@littledivy
Copy link
Member

Can you explain what you mean by that, and how it pertains to the code in question?

@crimsoncodes0 The code you are referring to (structuredClone) deals with for example globalThis.DataView and window.__bootstrap.primordials.DataView. So we now have 2 situations:

a. value is passed from userland i.e. globalThis.DataView - Users are allowed to manipulate value's dynamic accessors. (they own the value and how it behaves)

b. value is created internally i.e. window.__bootstrap.primordials.DataView - The getters for value are not prone to prototype pollution at all since window.__bootstrap.primordials.DataView was never exposed to userland.

@ghost
Copy link

ghost commented Jul 6, 2021

Can you explain what you mean by that, and how it pertains to the code in question?

@crimsoncodes0 The code you are referring to (structuredClone) deals with for example globalThis.DataView and window.__bootstrap.primordials.DataView. So we now have 2 situations:

a. value is passed from userland i.e. globalThis.DataView - Users are allowed to manipulate value's dynamic accessors. (they own the value and how it behaves)

b. value is created internally i.e. window.__bootstrap.primordials.DataView - The getters for value are not prone to prototype pollution at all since window.__bootstrap.primordials.DataView was never exposed to userland.

In situation "a," we obviously need to have the primordials in use to ensure correctness.

As for situation "b"... I don't think I understand the primordial code; how does one have both, a prototype copy, yet also retain correct semantics for comparing the user-provided object against the primordial prototype object via the instanceof operator?

@lucacasonato
Copy link
Member

@crimsoncodes0 You are correct we will need primordials for these too eventually. These primordials do not yet exist however, so there is nothing to change for this PR.

@bartlomieju bartlomieju merged commit 1aac477 into denoland:main Jul 6, 2021
@bartlomieju bartlomieju deleted the primordials_web branch July 6, 2021 12:38
@ghost
Copy link

ghost commented Jul 6, 2021

@crimsoncodes0 You are correct we will need primordials for these too eventually. These primordials do not yet exist however, so there is nothing to change for this PR.

From my read of the code, a deep primordial copy is made of both, ArrayBuffer, and TypedArray, so those changes are very possible already, unless I've misunderstood the setup there?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants